﻿// "Therefore those skilled at the unorthodox
// are infinite as heaven and earth,
// inexhaustible as the great rivers.
// When they come to an end,
// they bagin again,
// like the days and months;
// they die and are reborn,
// like the four seasons."
// 
// - Sun Tsu,
// "The Art of War"

using System;
using System.Diagnostics;
using System.Reflection;

namespace Infrastructure.Logging
{
    /// <summary>
    /// Guid diagnistic context class, used to set guid for guid property in the context.
    /// Guid property name: GuidDC
    /// </summary>
    public class GuidDC : IDisposable
    {
        /// <summary>
        /// Create operation guid logger, new guid is created.
        /// </summary>
        public GuidDC()
                : this(Guid.NewGuid())
        { }

        /// <summary>
        /// Create operation guid logger with the given guid.
        /// </summary>
        /// <param name="guid">the guid to use</param>
        public GuidDC(Guid guid)
        {
            Init(guid);
        }

        /// <summary>
        /// Create operation guid logger with the given guid.
        /// if null is given nothing is done.
        /// </summary>
        /// <param name="guid">the guid to use, can be null</param>
        public GuidDC(Guid? guid)
        {
            mIsGood = guid.HasValue;
            if (guid.HasValue)
                Init(guid.Value);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="guid">the guid to use</param>
        private void Init(Guid guid)
        {
            if (ThreadContext.Properties[GuidDCName] == null)
            {
                mIsGood = true;
                ThreadContext.Properties[GuidDCName] = guid;
            }
            else
            {
                mIsGood = false;
                // if an attempt to set the same guid, just ignore it
                // if it's a defferent guid, warn.
                if (!ThreadContext.Properties[GuidDCName].Equals(guid))
                    log.WarnFormat("Attempt to set operation guid when it already exist [{0}]",
                                   (new StackTrace()));
            }
        }

        /// <summary>
        /// get the current operation guid.
        /// </summary>
        public static Guid? CurrentGuid
        {
            get { return ThreadContext.Properties[GuidDCName] as Guid?; }
        }

        /// <summary>
        /// dispose of operation guid logger, clear the guid property in the log system.
        /// </summary>
        public void Dispose()
        {
            if (mIsGood)
                ThreadContext.Properties[GuidDCName] = null;
        }


        #region Data members

        /// <summary>
        /// logger
        /// </summary>
        private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

        /// <summary>
        /// the name of the property in the log system.
        /// </summary>
        private const string GuidDCName = "GuidDC";

        /// <summary>
        /// flag to indicate that the guid logger is ok, it false if 
        /// there is another guid logger the has set the operation guid.
        /// </summary>
        private bool mIsGood;

        #endregion
    }
}